package cn.cdeden.resource.unified.service.impl;

import cn.cdeden.common.core.domain.R;
import cn.cdeden.common.core.exception.ServiceException;
import cn.cdeden.common.core.utils.StringUtils;
import cn.cdeden.common.core.utils.file.FileUtils;
import cn.cdeden.common.oss.core.OssClientBucket;
import cn.cdeden.common.oss.entity.UploadResult;
import cn.cdeden.common.oss.enumd.OssBucketOneEnum;
import cn.cdeden.common.oss.enumd.OssModuleType;
import cn.cdeden.common.oss.factory.OssFactory;
import cn.cdeden.common.oss.util.FileProcessingUtil;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.resource.api.domain.*;
import cn.cdeden.resource.domain.SysOssDownloadRecord;
import cn.cdeden.resource.domain.SysOssSlice;
import cn.cdeden.resource.domain.dto.FilePrintLogDto;
import cn.cdeden.resource.domain.vo.SysOssSliceVo;
import cn.cdeden.resource.domain.vo.SysOssVo;
import cn.cdeden.resource.service.FilePrintLogService;
import cn.cdeden.resource.service.ISysOssDownloadRecordService;
import cn.cdeden.resource.service.ISysOssService;
import cn.cdeden.resource.service.ISysOssSliceService;
import cn.cdeden.resource.unified.domain.dto.FilesCoverUploadDto;
import cn.cdeden.resource.unified.domain.dto.FilesUploadDto;
import cn.cdeden.resource.unified.domain.dto.OnlinePreviewInfoDto;
import cn.cdeden.resource.unified.domain.dto.SliceFileUploadDto;
import cn.cdeden.resource.unified.service.RemoteUploadFileFilter;
import cn.cdeden.resource.unified.service.UnifiedFileUploadService;
import cn.cdeden.resource.utils.FileUtil;
import cn.cdeden.system.api.model.LoginUser;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.services.s3.model.CompletedPart;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @ProjectName : KnowCore
 * @Package : cn.cdeden.resource.unified.service.impl
 * @ClassName : UnifiedFileUploadServiceImpl
 * @Author : Yu.
 * @Description : // TODO
 * @Date : 2024/12/24 15:29
 * @Version : 1.0
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class UnifiedFileUploadServiceImpl implements UnifiedFileUploadService {


    private final ISysOssService ossService;


    private final ISysOssSliceService ossSliceService; //分片上传


    private final ISysOssDownloadRecordService downloadService;  //下载记录


    private final FilePrintLogService filePrintLogService; //文件打印日志


    private final RemoteUploadFileFilter unificationFile;

    /**
     * 单文件上传
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/5 13:40
     **/
    @Override
    public R upload(FilesUploadDto uploadDto) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        MultipartFile multipartFile = uploadDto.getFile();
        Long fileSize = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();
        String fileName = FileUtil.getPrefix(uploadDto.getFileName() != null ? uploadDto.getFileName() : originalFilename); //文件名
        long size = FileProcessingUtil.FILE_SIZE;
        //// 检查文件夹大小
        if (ObjectUtils.isNotEmpty(fileSize) && FileProcessingUtil.sizeComparison(size, fileSize)) {
            throw new RuntimeException("超过文件上传大小限制:" + FileProcessingUtil.getSizeToUnit(size) + ",上传的文件大小:" + FileProcessingUtil.getSizeToUnit(fileSize) + "");
        }
        //// 检查文件格式是否正确
        String extName = FileProcessingUtil.extName(originalFilename); //文件拓展名
        if (!FileProcessingUtil.getFileSuffixBy(extName)) {
            throw new RuntimeException("不可以上传文件格式:`" + extName + "`");
        }
        //// 验证数据  放回 数据  可以生成 历史版本码 直接纯到对应 库中去
        unificationFile.gssUploadService(uploadDto.getType());

        RemoteOssUpload remoteOssUpload = unificationFile.verifyData(  //验证数据
            RemoteOssUpload.builder()
                .fileName(fileName)
                .fileSuffix(extName)
                .filePath(uploadDto.getFilePath())
                .fileId(uploadDto.getModuleId())
                .remarks(uploadDto.getRemarks())
                .parentId(uploadDto.getParentId())
                .fileSize(fileSize)
                .info(uploadDto.getInfo())
                .type(uploadDto.getType())
                .build(),
            loginUser.getUserId(),
            uploadDto.getType()
        );
        if (remoteOssUpload == null) {
            return R.fail("上传失败");
        }

        String moduleId = remoteOssUpload.getFileId();
        uploadDto.setModuleId(moduleId); //获取版本然后覆
        uploadDto.setFileName(remoteOssUpload.getFileName());

        //上传 到文件库库
        SysOssVo ossInfo = this.ordinaryUpload(loginUser, uploadDto, remoteOssUpload.getBrandName());

        return ordinaryUploadZip(ossInfo, remoteOssUpload, loginUser, uploadDto);
    }

    @Override
    public R uploadCoverImage(FilesCoverUploadDto uploadDto) {



        return null;
    }


    /**
     * 压缩包是否解压上传处理
     *
     * @param ossInfo         oss信息
     * @param remoteOssUpload 上传的信息
     * @param loginUser       用户信息
     * @param uploadDto       上传信息
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/25 9:39
     **/
    public R ordinaryUploadZip(SysOssVo ossInfo, RemoteOssUpload remoteOssUpload, LoginUser loginUser, FilesUploadDto uploadDto) {
//文件 告知服务进行写入
        JSONObject uploadInfo = remoteOssUpload.getInfo();
        String fileSuffix = ossInfo.getFileSuffix();
        // 文件 告知服务进行写入
        RemoteFilesUpload build = RemoteFilesUpload.builder()
            .storageId(String.valueOf(ossInfo.getOssId()))
            .versionId(ossInfo.getVersionId())
            .versionName(ossInfo.getVersionName())
            .fileSize(ossInfo.getFileSize())
            .fileSuffix(fileSuffix)
            .fileName(ossInfo.getOriginalName())
            .filePath(remoteOssUpload.getFilePath())
            .parentId(remoteOssUpload.getParentId())
            .info(uploadInfo) //模块的参数
            .url(ossInfo.getUrl())
            .remarks(remoteOssUpload.getRemarks())
            .type(remoteOssUpload.getType())
            .build();

        if (StringUtils.equals(fileSuffix, "zip") && uploadDto.isUnzip()) {
            try {
//                List data = zipFileThread(build, loginUser, uploadDto,remoteOssUpload.getBrandName(), ossInfo.getOssId());
                List data = zipFileThreadIn(build, loginUser, uploadDto, remoteOssUpload.getBrandName(), ossInfo.getOssId());
                ossService.deleteWithValidByIds(Arrays.asList(ossInfo.getOssId()), false); //删除临时的文件
                return R.ok(data);
            } catch (Exception e) {
                log.error("解压失败", e);
                RemoteFilesBucketPath upload = unificationFile.upload(
                    build,
                    loginUser.getUserId(),
                    uploadDto.getType()
                );//保存数据 到 模块 数据
                return R.ok(upload.getInfo());
            }

        } else {
            RemoteFilesBucketPath upload = unificationFile.upload(
                build,
                loginUser.getUserId(),
                uploadDto.getType()
            );//保存数据 到 模块 数据
            return R.ok(upload.getInfo());
        }
    }


    /**
     * 创建分片信息
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/5 13:40
     **/
    @Override
    public R createMultipartUpload(SliceFileUploadDto uploadDto) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        Long fileSize = uploadDto.getFileSize();
        String fileName = uploadDto.getFileName(); //文件名
        long size = 1048576L * 200; //文件限制的 200M
        //// 检查文件夹大小
        if (ObjectUtils.isNotEmpty(fileSize) && FileProcessingUtil.sizeComparison(size, fileSize)) {
            throw new RuntimeException("超过文件上传大小限制:" + FileProcessingUtil.getSizeToUnit(size) + ",上传的文件大小:" + FileProcessingUtil.getSizeToUnit(fileSize) + "");
        }
        //// 检查文件格式是否正确
        String extName = uploadDto.getSuffix(); //文件拓展名
        if (!FileProcessingUtil.getFileSuffixBy(extName)) {
            throw new RuntimeException("不可以上传文件格式:`" + extName + "`");
        }
        //// 验证数据  放回 数据  可以生成 历史版本码 直接纯到对应 库中去
        unificationFile.gssUploadService(uploadDto.getType());

        RemoteOssUpload remoteOssUpload = unificationFile.verifyData(  //验证数据
            RemoteOssUpload.builder()
                .fileName(fileName)
                .fileSuffix(extName)
                .filePath(uploadDto.getFilePath())
                .fileId(uploadDto.getModuleId())
                .remarks(uploadDto.getRemarks())
                .parentId(uploadDto.getParentId())
                .fileSize(fileSize)
                .info(uploadDto.getInfo())
                .type(uploadDto.getType())
                .build(),
            loginUser.getUserId(),
            uploadDto.getType()
        );
        if (remoteOssUpload == null) {
            return R.fail("上传失败");
        }
//        创建分片信息
        SysOssSliceVo multipartUpload = this.createMultipartUpload(loginUser, uploadDto, remoteOssUpload);
        return R.ok(multipartUpload);
    }

    /**
     * 上传分片文件
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/22 17:06
     **/
    @Override
    public R uploadSlice(SliceFileUploadDto uploadDto) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        Long fileSize = uploadDto.getFileSize();
        String fileName = uploadDto.getFileName(); //文件名
        MultipartFile file = uploadDto.getFile();
        if (ObjectUtils.isEmpty(file)) {
            throw new RuntimeException("上传的分片文件不可以为空");
        }

        SysOssVo ossInfo = this.sliceFileUpload(loginUser, uploadDto);
        if (ossInfo.getOssId() != null) {
            SysOssSlice sliceInfo = ossInfo.getSliceInfo();
            JSONObject jsonObject = JSONObject.parseObject(sliceInfo.getInfo());
            RemoteOssUpload ossUpload = jsonObject.getObject("ossUpload", RemoteOssUpload.class);
            return ordinaryUploadZip(ossInfo, ossUpload, loginUser, uploadDto.toFilesUploadDto());
//            RemoteFilesBucketPath upload = unificationFile.upload(
//                RemoteFilesUpload.builder()
//                    .storageId(String.valueOf(ossInfo.getOssId()))
//                    .versionId(ossInfo.getVersionId())
//                    .versionName(ossInfo.getVersionName())
//                    .fileSize(ossInfo.getFileSize())
//                    .fileSuffix(ossInfo.getFileSuffix())
//                    .fileName(ossInfo.getOriginalName())
//                    .filePath(uploadDto.getFilePath())
//                    .parentId(uploadDto.getParentId())
//                    .info(uploadDto.getInfo()) //模块的参数
//                    .url(ossInfo.getUrl())
//                    .remarks(uploadDto.getRemarks())
//                    .type(uploadDto.getType())
//                    .build(),
//                loginUser.getUserId(),
//                uploadDto.getType()
//            );//保存数据 到 模块 数据
//            return R.ok(upload.getInfo());
        }
        return R.ok(ossInfo);
    }


    /**
     * 中止分片文件上传
     *
     * @param userInfo 操作的用户
     * @param sliceId  分片上传的ID
     * @return java.lang.Boolean
     * @author Yu.
     * @Date 2024/12/22 16:37
     **/
    @Override
    public Boolean abortSliceFileUpload(LoginUser userInfo, String sliceId) {
        SysOssSlice sliceInfo = ossSliceService.getById(sliceId); //获取分片上传信息
        if (ObjectUtils.isEmpty(sliceInfo)) {
            throw new ServiceException("分片上传信息不存在");
        }
        OssClientBucket storage = OssFactory.instanceBucket(sliceInfo.getService()); //获取服务商
        storage.abortMultipartUpload(sliceInfo.getBucketName(), sliceInfo.getFileName(), sliceInfo.getETag());
        ossSliceService.removeById(sliceId);//删除分片上传记录
        return true;
    }


    /**
     * 移动文件位置
     *
     * @param ossId
     * @param versionId
     * @param bucketName 移动文件位置
     * @return cn.cdeden.resource.domain.vo.SysOssVo
     * @author Yu.
     * @Description // TODO
     * @Date 2024/12/11 19:11
     **/
    @Override
    public SysOssVo movePosition(Long ossId, String versionId, String bucketName) {
//        SysOssVo sysOssVo = ossService.getByIdAndVersionId(ossId, versionId);
//        OssClientBucket storage = OssFactory.instanceBucket(sysOssVo.getService());
//        UploadResult uploadResult = storage.copy(
//            sysOssVo.getFileName(),
//            sysOssVo.getFileSuffix(),
//            sysOssVo.getBucketName(),
//            sysOssVo.getVersionId(),
//            bucketName
//        );


        return null;
    }


    /**
     * 复制文件
     *
     * @param ossId      上传的文件编号
     * @param versionId  文件版本
     * @param bucketName 移动文件位置
     * @return cn.cdeden.resource.domain.vo.SysOssVo
     * @author Yu.
     * @Date 2024/12/11 19:10
     **/
    @Override
    public SysOssVo copyFile(Long ossId, String versionId, String bucketName) {
        SysOssVo sysOssVo = ossService.getByIdAndVersionId(ossId, versionId);
        OssClientBucket storage = OssFactory.instanceBucket(sysOssVo.getService());
        UploadResult uploadResult = storage.copy(
            sysOssVo.getFileName(),
            sysOssVo.getFileSuffix(),
            sysOssVo.getBucketName(),
            sysOssVo.getVersionId(),
            bucketName
        );
        SysOssVo ossInfo = ossService.buildResultEntity(
            sysOssVo.getOriginalName(),
            sysOssVo.getFileSuffix(),
            storage.getConfigKey(),
            uploadResult,
            sysOssVo.getModuleTypeInfo()
        );
        return ossInfo;
    }


    /**
     * 下载文件
     *
     * @param downloads  下载文件信息
     * @param moduleType 文件模块
     * @param request    请求
     * @param response   相应
     * @return void
     * @author Yu.
     * @Date 2024/12/11 19:11
     **/
    @Override
    public void download(List<RemoteFilesDownload> downloads, String moduleType, HttpServletRequest request, HttpServletResponse response) throws IOException {
        Set<Long> storageIds = downloads.stream()
            .map(RemoteFilesDownload::getStorageId)
            .filter(key -> key != null && !key.isEmpty())
            .map(Long::parseLong)
            .collect(Collectors.toSet());
        downloads.forEach(download -> {
            String storageId = download.getStorageId();
            if (storageId != null) {
                SysOssVo ossVo = ossService.getByIdAndVersionId(Long.parseLong(storageId), download.getVersionId());
                if (ObjectUtil.isNotEmpty(ossVo)) {
                    // 判断文件类型 不等于 直接通过
//                    if (!moduleType.equals("all") && !moduleType.equals(ossVo.getModuleType()))
//                        throw new ServiceException("文件类型不一致");
                    download.setService(ossVo.getService());
                    download.setBucketName(ossVo.getBucketName());
                    download.setKey(ossVo.getFileName());
                    download.setVersionId(ossVo.getVersionId());
                    download.setVersionName(ossVo.getVersionName());
                }
            }
        });
        List<String> collect = downloads.stream()
            .map(RemoteFilesDownload::getKey)
            .filter(key -> key != null && !key.isEmpty())
            .collect(Collectors.toList());
        if (collect.size() == 1) {
            RemoteFilesDownload download = downloads.stream().filter(e -> !e.isFolder()).toList().get(0);
            FileUtils.setAttachmentResponseHeader(response, download.getFileNameSuffix());
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
            OssClientBucket storage = OssFactory.instanceBucket(download.getService());
            long contentLength = storage.downloadAsynchronous(download.getBucketName(), download.getKey(), download.getVersionId(), response.getOutputStream());
            response.setContentLengthLong(contentLength);
            download.setLibraryType(moduleType); //当前的模块
            boolean save = downloadService.save(download, request); //保存下载记录
        } else if (collect.size() > 1) {
            response.setContentType("application/zip");
//            String percentEncodedFileName = FileUtils.percentEncode(downloads.get(0).getFileNameSuffix() + "_等" + collect.size() + "个文件.zip");
            String percentEncodedFileName = downloads.get(0).getFileNameSuffix() + "_等" + collect.size() + "个文件.zip";
            FileUtils.setAttachmentResponseHeader(response, percentEncodedFileName);
//            long contentLength = downloads.stream()
//                .mapToLong(RemoteFilesDownload::getFileSize)
//                .sum();
            downloads = RemoteFilesDownload.listToTerr(downloads, downloads.get(0).getLibraryType()); //设置层级
            if (downloads.size() <= 0) {
                throw new ServiceException("获取参数问题,无法完成文件的批量下载");
            }

            Stack<RemoteFilesDownload> stack = new Stack<>();
            for (RemoteFilesDownload files : downloads) {
                files.setDownloadPath(StringUtils.EMPTY);
                stack.push(files);
            }
            List<SysOssDownloadRecord> recordList = new ArrayList<>();
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
                while (!stack.isEmpty()) {
                    RemoteFilesDownload current = stack.pop();
                    boolean folder = current.isFolder();
                    String downloadPath = current.getDownloadPath();
                    String currentRealName = current.getFileName();
                    if (folder && CollectionUtils.isNotEmpty(current.getChildren())) {
                        String childDownloadPath = downloadPath + currentRealName + File.separator;
                        ZipEntry zipEntry = new ZipEntry(childDownloadPath);
                        zipOutputStream.putNextEntry(zipEntry);
                        List<RemoteFilesDownload> children = current.getChildren();
                        for (RemoteFilesDownload child : children) {
                            // 为文件夹内文件设置下载路径
                            child.setDownloadPath(childDownloadPath);
                            stack.push(child);
                        }
                    } else if (!folder) {
                        // 如果是文件，则直接添加到压缩包
                        String name = currentRealName + "." + current.getFileSuffix();
//                        String name = currentRealName ;
                        downloadToZipFile(current.getBucketName(), current.getKey(), current.getVersionId(), current.getService(), name, downloadPath, zipOutputStream);//下载文件
                        current.setLibraryType(moduleType); //当前的模块
                    }
                    recordList.add(downloadService.generate(current, request)); //构建下载记录
                }
                if (!recordList.isEmpty()) {
                    downloadService.saveList(recordList); //保存下载记录
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            throw new ServiceException("请选择要下载的文件");
        }

    }

    /**
     * 下载文件到zip包中
     *
     * @param bucketName      桶的名称
     * @param objectName      // 文件在桶中的位置
     * @param versionId       版本
     * @param service         服务的供应商
     * @param fileName        文件名
     * @param downloadPath    下载路径
     * @param zipOutputStream zip输出流
     */
    public void downloadToZipFile(String bucketName, String objectName, String versionId, String service, String fileName, String downloadPath, ZipOutputStream zipOutputStream) {
        OssClientBucket storage = OssFactory.instanceBucket(service);
        try {
            zipOutputStream.putNextEntry(new ZipEntry(downloadPath + fileName));
            storage.downloadZip(bucketName, objectName, versionId, zipOutputStream);
            zipOutputStream.closeEntry();
            System.out.println("Added to ZIP: " + fileName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 文件打印
     * 文件转成 pdf 流方式返回前端
     *
     * @param printFileDto
     * @return void
     * @Date 2024/12/12 17:16
     **/
    @Override
    public void convertPdf(RemoteFile fileDataInfo, OnlinePreviewInfoDto printFileDto, HttpServletResponse response) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        SysOssVo byId = ossService.getById(fileDataInfo.getOssId());
        OssClientBucket bucket = OssFactory.instanceBucket(byId.getService());
        String privateUrl = bucket.getPrivateUrl(byId.getBucketName(), byId.getFileName(), byId.getVersionId(), 120);


        String suffix = fileDataInfo.getFileSuffix();
        String documentType = cn.cdeden.resource.utils.FileUtil.getDocumentType(suffix);
        String key = byId.getVersionId();
        String responseUrl = null;
        if (suffix.equals("pdf")) {
            responseUrl = privateUrl;
        } else if (documentType.equals("word") || documentType.equals("excel")) {
            responseUrl = cn.cdeden.resource.utils.FileUtil.convertToPdf(privateUrl, suffix, key, "pdf", key + ".pdf");
        }
        response.setContentType("application/x-download");
        response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
        try {
            URL url = new URL(responseUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            InputStream inputStream = connection.getInputStream();

            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            inputStream.close();
            outputStream.close();
            connection.disconnect();
        } catch (Exception e) {
            throw new RuntimeException("转换失败:" + e.getMessage());
        }

        FilePrintLogDto filePrintLogDto = new FilePrintLogDto();
        filePrintLogDto.setPrinterId(loginUser.getUserId());
        filePrintLogDto.setTreeNodeId(Long.valueOf(printFileDto.getModuleId()));
        filePrintLogDto.setLibraryType(printFileDto.getType());
        filePrintLogDto.setCount(1);
        filePrintLogService.save(filePrintLogDto);

    }


    /**
     *  工具方法
     **/


    /**
     * 压缩文件 写硬盘 多线程 解压并上传到个个库中去
     *
     * @param upload
     * @param loginUser
     * @param uploadDto
     * @param brandName
     * @param ossId
     * @return java.util.List
     * @author Yu.
     * @Date 2024/12/27 16:18
     **/
    public List zipFileThread(RemoteFilesUpload upload, LoginUser loginUser, FilesUploadDto uploadDto, String brandName, Long ossId) {
        SysOssVo sysOss = ossService.getById(ossId);
        String fileSuffix = sysOss.getFileSuffix();
        OssModuleType typeEnum = uploadDto.getTypeEnum();  // 获取文件模块


        if (StringUtils.equals(fileSuffix, "zip")) {
            String substring = sysOss.getFileName().substring(0, sysOss.getFileName().lastIndexOf("."))
                .replaceAll("/", "");
            String rootPath = System.getProperty("user.dir");
            String pathname = rootPath + File.separator + "file" + File.separator + substring;
            String filePath = pathname + "." + fileSuffix;
            OssClientBucket storage = OssFactory.instanceBucket(sysOss.getService());
            storage.downloadToFile(sysOss.getBucketName(), sysOss.getFileName(), filePath);
            try (ZipFile zipFile = new ZipFile(filePath)) {
                Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
                List<Callable<RemoteFilesBucketPath>> tasks = new ArrayList<>();
                long size = FileProcessingUtil.FILE_SIZE;
                while (entries.hasMoreElements()) {
                    ZipArchiveEntry entry = entries.nextElement();
                    // 创建目录（如果是目录条目）
                    if (entry.isDirectory()) {
                        continue;
                    }
                    String name = entry.getName();
                    File file1 = new File(name);
                    String fileName = file1.getName(); // 获取文件名
                    String path = file1.getParent(); // 获取路径（不包括文件名部分）

                    String prefix = FileUtil.getPrefix(fileName);
                    String zipSuffix = FileUtil.extName(fileName);
                    long fileSize = entry.getSize();
                    // 检查文件夹大小
                    if (ObjectUtils.isNotEmpty(fileSize) && fileSize > 0 && FileProcessingUtil.sizeComparison(size, fileSize)) {
                        log.error("超过文件上传大小限制: {},上传的文件大小:{}", FileProcessingUtil.getSizeToUnit(size), FileProcessingUtil.getSizeToUnit(fileSize));
                        continue;
                    }
                    if (!FileProcessingUtil.getFileSuffixBy(zipSuffix)) {
                        log.error("不可以上传文件格式: {},文件名称:{}", zipSuffix, fileName);
                        continue;
                    }
                    log.error("name2: {}, 干净的文件名称: {}, 后缀名称: {}", name, fileName, zipSuffix);
                    try (InputStream is = zipFile.getInputStream(entry)) {
                        MockMultipartFile file = new MockMultipartFile(fileName, is);

                        // 添加处理文件的任务
                        tasks.add(() -> {
                            // 上传文件
                            try {
                                // 上传到 OSS 服务中去
                                UploadResult uploadResult = storage.uploadSuffix(file, zipSuffix, brandName);

                                SysOssVo ossInfo = ossService.buildResultEntity(prefix, zipSuffix, storage.getConfigKey(), uploadResult, typeEnum);

                                // 保存文件信息
                                RemoteFilesUpload clone = RemoteFilesUpload.builder()
                                    .storageId(String.valueOf(ossInfo.getOssId()))
                                    .versionId(ossInfo.getVersionId())
                                    .versionName(ossInfo.getVersionName())
                                    .fileSize(ossInfo.getFileSize())
                                    .fileSuffix(zipSuffix)
                                    .fileName(ossInfo.getOriginalName())
                                    .filePath(uploadDto.getFilePath())
                                    .parentId(uploadDto.getParentId())
                                    .info(uploadDto.getInfo()) // 模块的参数
                                    .url(ossInfo.getUrl())
                                    .remarks(uploadDto.getRemarks())
                                    .type(uploadDto.getType())
                                    .build();
                                clone.setPath(path); // 设置文件的路径
                                try {
                                    RemoteFilesBucketPath upload1 = unificationFile.upload(
                                        clone,
                                        loginUser.getUserId(),
                                        uploadDto.getType()
                                    );
                                    if (upload1 != null) {
                                        // 保存数据到模块数据
//                                        synchronized (recordList) {
//                                            recordList.add(upload1.getInfo());
//                                        }
                                        return upload1;
                                    }
                                } catch (Exception e) {
                                    ossService.deleteWithValidByIds(Arrays.asList(ossInfo.getOssId()), false);
                                }
                            } catch (IOException e) {
                                log.error("文件上传失败: {}", fileName, e);

                            }
                            return null;
                        });
                    } catch (IOException e) {
                        log.error("文件上传失败: {}", fileName, e);
                    }
                }
                // 提交所有任务并等待完成
                return invokeAll(tasks);
            } catch (Exception e) {
                throw new ServiceException("zip解压失败", e);
            } finally {
                try {
                    org.apache.commons.io.FileUtils.delete(new File(filePath));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        } else {
            throw new ServiceException("文件不是zip文件");
        }
    }


    /**
     * 压缩文件 流的方式 多线程 解压并上传到个个库中去
     *
     * @param upload
     * @param loginUser
     * @param uploadDto
     * @param brandName
     * @param ossId
     * @return java.util.List
     * @author Yu.
     * @Date 2024/12/26 18:09
     **/
    public List zipFileThreadIn(RemoteFilesUpload upload, LoginUser loginUser, FilesUploadDto uploadDto, String brandName, Long ossId) {
        log.info("进入zipFileThreadIn方法");
        SysOssVo sysOss = ossService.getById(ossId);
        String fileSuffix = sysOss.getFileSuffix();
        OssModuleType typeEnum = uploadDto.getTypeEnum();  // 获取文件模块
        List recordList = new ArrayList();

        if (StringUtils.equals(fileSuffix, "zip")) {
            // 直接下载到 InputStream
            OssClientBucket storage = OssFactory.instanceBucket(sysOss.getService());
            try (InputStream inputStream = storage.downloadToInputStream(sysOss.getBucketName(), sysOss.getFileName())) {
                try (ZipInputStream zipInS = new ZipInputStream(inputStream, Charset.forName("GBK"))) {
                    List<Callable<RemoteFilesBucketPath>> tasks = new ArrayList<>();
                    log.info("zip解压开始-GBK");
                    long size = FileProcessingUtil.FILE_SIZE;
                    ZipEntry entry;
                    // 逐个读取 zip 条目
                    while ((entry = zipInS.getNextEntry()) != null) {
                        // 跳过目录
                        if (entry.isDirectory()) {
                            continue;
                        }
                        String name = entry.getName();
                        File file1 = new File(name);
                        String fileName = file1.getName(); // 获取文件名
                        String path = file1.getParent(); // 获取路径（不包括文件名部分）

                        String prefix = FileUtil.getPrefix(fileName);
                        String zipSuffix = FileUtil.extName(fileName);

                        long fileSize = entry.getSize();
                        //// 检查文件夹大小
                        if (ObjectUtils.isNotEmpty(fileSize) && fileSize > 0 && FileProcessingUtil.sizeComparison(size, fileSize)) {
                            log.error("超过文件上传大小限制: {},上传的文件大小:{}", FileProcessingUtil.getSizeToUnit(size), FileProcessingUtil.getSizeToUnit(fileSize));
                            continue;
                        }
                        if (!FileProcessingUtil.getFileSuffixBy(zipSuffix)) {
                            log.error("不可以上传文件格式: {},文件名称:{}", zipSuffix, fileName);
                            continue;
                        }
                        log.error("name2: {}, 干净的文件名称: {}, 后缀名称: {}", name, fileName, zipSuffix);
                        // 添加处理文件的任务
                        ZipEntry finalEntry = entry;
                        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream)) {

                            byte[] buffer = new byte[1024];
                            int length;
                            while ((length = zipInS.read(buffer)) != -1) {
                                bufferedOutputStream.write(buffer, 0, length);
                            }
                            bufferedOutputStream.flush();
                            byte[] byteArray = byteArrayOutputStream.toByteArray();
                            log.info("读取条目 {} 的数据长度: {}", finalEntry.getName(), byteArray.length);
                            tasks.add(() -> {
                                try {
                                    // 上传到 OSS 服务中去
                                    UploadResult uploadResult = storage.uploadSuffix(byteArray, zipSuffix, null, brandName);

                                    SysOssVo ossInfo = ossService.buildResultEntity(prefix, zipSuffix, storage.getConfigKey(), uploadResult, typeEnum, loginUser);

                                    // 保存文件信息
                                    RemoteFilesUpload clone = RemoteFilesUpload.builder()
                                        .storageId(String.valueOf(ossInfo.getOssId()))
                                        .versionId(ossInfo.getVersionId())
                                        .versionName(ossInfo.getVersionName())
                                        .fileSize(ossInfo.getFileSize())
                                        .fileSuffix(zipSuffix)
                                        .fileName(ossInfo.getOriginalName())
                                        .filePath(uploadDto.getFilePath())
                                        .parentId(uploadDto.getParentId())
                                        .info(uploadDto.getInfo()) // 模块的参数
                                        .url(ossInfo.getUrl())
                                        .remarks(uploadDto.getRemarks())
                                        .type(uploadDto.getType())
                                        .build();
                                    clone.setPath(path); // 设置文件的路径

                                    try {
                                        RemoteFilesBucketPath upload1 = unificationFile.upload(
                                            clone,
                                            loginUser.getUserId(),
                                            uploadDto.getType()
                                        );
                                        if (upload1 != null) {
                                            return upload1;
                                        }
                                    } catch (Exception e) {
                                        ossService.deleteWithValidByIds(Arrays.asList(ossInfo.getOssId()), false);
                                    }
                                } catch (Exception e) {
                                    log.error("文件上传失败: {}", fileName, e);

                                } finally {
                                    // 确保每次读取一个条目后都关闭该条目
                                    zipInS.closeEntry();
                                }

                                return null;
                            });
                        }
                    }
                    // 提交所有任务并等待完成
                    return invokeAll(tasks);
                } catch (Exception e) {
                    throw new ServiceException("zip解压失败", e);
                }
            } catch (IOException e) {
                throw new ServiceException("下载文件失败", e);
            }
        } else {
            throw new ServiceException("文件不是zip文件");
        }
    }

    /**
     * 批量执行任务
     *
     * @param tasks
     * @throws InterruptedException
     */
    private List invokeAll(List<Callable<RemoteFilesBucketPath>> tasks) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建一个线程池
        List recordList = new ArrayList();
        List<Future<RemoteFilesBucketPath>> futures = executorService.invokeAll(tasks);
        for (Future<RemoteFilesBucketPath> future : futures) {
            try {
                RemoteFilesBucketPath bucketPath = future.get(); // 等待任务执行完成
                if (bucketPath != null) {
                    recordList.add(bucketPath.getInfo());
                }


            } catch (InterruptedException | ExecutionException e) {
                log.error("任务执行失败", e);
            }
        }
        executorService.shutdown(); // 关闭线程池
        return recordList;
    }


    /**
     * 上传文件到 oss
     *
     * @param userInfo
     * @param uploadDto
     * @param brandName
     * @return cn.cdeden.resource.domain.vo.SysOssVo
     * @author Yu.
     * @Date 2024/12/24 15:48
     **/
    private SysOssVo ordinaryUpload(LoginUser userInfo, FilesUploadDto uploadDto, String brandName) {
        OssClientBucket storage = OssFactory.instanceBucket();
        UploadResult uploadResult = null;
        MultipartFile file = uploadDto.getFile();
        MultipartFile fileImage = uploadDto.getCoverImage();

        boolean fileImageB = fileImage != null;
        String coverSuffix = fileImageB ? FileUtil.extName(fileImage.getOriginalFilename()) : null;


        String originalFilename = file.getOriginalFilename();
        String suffix = FileUtil.extName(originalFilename); //文件拓展名
        String fileName = uploadDto.getFileName() != null ? uploadDto.getFileName() : FileUtil.getPrefix(originalFilename); //文件名

        String storageId = uploadDto.getModuleId(); //获取 在oss中的数据
        OssModuleType typeEnum = uploadDto.getTypeEnum(); ////获取 文件模块
        byte[] bytes = new byte[0];
        byte[] bytesImage = null;
        try {
            bytes = file.getBytes();
            bytesImage = fileImageB ? fileImage.getBytes() : null;
        } catch (IOException e) {
            log.error("文件上传失败:{}", e.getMessage());
            throw new ServiceException(e.getMessage());
        }
        SysOssVo ossVo = null;
        try {
            String fileContentType = file.getContentType();
            String coverContentType = fileImageB ? fileImage.getContentType() : null;

            if (StringUtils.isNotEmpty(storageId)) {
                ossVo = ossService.getById(Long.valueOf(storageId));
                if (ossVo == null) {
                    throw new ServiceException("文件不存在无法上传");
                }
//                uploadResult = storage.uploadSuffix(bytes, suffix, fileContentType, ossVo.getBucketName(), ossVo.getFileName());
                String coverName = ossVo.getCoverName();
                if (StringUtils.isNotEmpty(coverName) && fileImageB) {
//                    删除旧的的封面信息
                    storage.delete(OssBucketOneEnum.PUBLIC_IMAGES.getCode(), ossVo.getCoverUrl());
                }

                uploadResult = storage.uploadCoverImageSuffix(bytes,
                    fileContentType,
                    ossVo.getBucketName(),
                    ossVo.getFileName(),
                    bytesImage,
                    coverSuffix,
                    coverContentType);

                // 保存文件信息
                ossVo = ossService.update(ossVo.getOssId(), uploadResult, typeEnum, null);

            } else {

                uploadResult = storage.uploadCoverImageSuffix(
                    bytes,
                    bytesImage,
                    suffix,
                    fileContentType,
                    brandName != null ? brandName : OssBucketOneEnum.TEMPORARY_FILES.getCode(),
                    coverSuffix,
                    coverContentType
                );

                // 保存文件信息
                ossVo = ossService.buildResultEntity(fileName, suffix, storage.getConfigKey(), uploadResult, typeEnum);
            }
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new ServiceException("上传文件失败");
        }
        return ossVo;

    }


    @Transactional
    public SysOssSliceVo createMultipartUpload(LoginUser userInfo, SliceFileUploadDto uploadDto, RemoteOssUpload ossUpload) {
        OssClientBucket storage = OssFactory.instanceBucket();
        String suffix = uploadDto.getSuffix(); //文件拓展名
        UploadResult upload = storage.createMultipartUpload(ossUpload.getBrandName(), suffix); //创建分片上传
        upload.setFileMd5(upload.getFileMd5());
        return ossSliceService.insertByUpload(upload, storage.getConfigKey(), uploadDto, ossUpload);
    }

    @Transactional
    public SysOssVo sliceFileUpload(LoginUser userInfo, SliceFileUploadDto uploadDto) {
        String sliceId = uploadDto.getSliceId();
        SysOssSlice sliceInfo = ossSliceService.getById(sliceId); //获取分片上传信息
        if (ObjectUtils.isEmpty(sliceInfo)) {
            throw new ServiceException("分片上传信息不存在");
        }
        byte[] bytes = new byte[0];
        try {
            bytes = uploadDto.getFile().getBytes();
        } catch (IOException e) {
            log.error("文件上传失败:{}", e.getMessage());
            throw new ServiceException(e.getMessage());
        }
        OssClientBucket storage = OssFactory.instanceBucket(sliceInfo.getService()); //获取服务商 上传文件
        CompletedPart completedPart = storage.uploadPart(
            sliceInfo.getBucketName(),
            sliceInfo.getFileName(),
            bytes,
            sliceInfo.getETag(),
            uploadDto.getPartNumber(),
            sliceInfo.getPartSize(),
            sliceInfo.getFileSize()
        );
        String sliceFile = storage.sliceFileFinish(sliceInfo.getBucketName(), sliceInfo.getFileName(), sliceInfo.getETag(), sliceInfo.getPartNumber());
        if (sliceFile == null) {
            UploadResult uploadResult = storage.completeMultipartUpload(sliceInfo.getBucketName(), sliceInfo.getFileName(), sliceInfo.getETag(), sliceInfo.getPartNumber());//合并文件
            uploadResult.setFileMd5(sliceInfo.getFileMd5()); //文件的md5
            uploadResult.setFileSize(sliceInfo.getFileSize()); //文件大小
            ossSliceService.removeById(sliceId); //删除完成上传的分片记录
            SysOssVo sysOssVo = ossService.buildResultEntity(sliceInfo.getOriginalName(), sliceInfo.getFileSuffix(), storage.getConfigKey(), uploadResult, OssModuleType.findCoedInfo(sliceInfo.getModuleType()));
            sysOssVo.setSliceInfo(sliceInfo);
            return sysOssVo;
        }

        return SysOssVo.builder()
            .versionName(completedPart.eTag())
            .versionId(String.valueOf(completedPart.partNumber()))
            .build();
    }


}
